package movepaint.stateMachine;

import fr.lri.swingstates.canvas.CPolyLine;
import fr.lri.swingstates.canvas.CStateMachine;
import fr.lri.swingstates.canvas.Canvas;
import fr.lri.swingstates.gestures.Gesture;
import fr.lri.swingstates.sm.State;
import fr.lri.swingstates.sm.Transition;
import fr.lri.swingstates.sm.transitions.Drag;
import fr.lri.swingstates.sm.transitions.KeyPress;
import fr.lri.swingstates.sm.transitions.Press;
import fr.lri.swingstates.sm.transitions.Release;
import fr.lri.swingstates.sm.transitions.TimeOut;
import java.awt.event.KeyEvent;
import java.awt.geom.Point2D;
import movepaint.GestureRecognition;
import movepaint.stateMachine.InkMachine;

/**
 * Machine a état utilisée pour le dessin libre (crayon) et le tracage de segment.
 * @author Paulino A.
 * @version 1.0
 */
public class FreeDrawMachine extends CStateMachine {
    private Canvas _canvas;                 // Référence au canvas de la frame
    private GestureRecognition _frameMain;  // Référence à la frame principale
    private Gesture _gesture;
    private Point2D _pInit;
    private CPolyLine _ink;

    // Textes des astuces!!
    private final static String TIP_DESSINER_SEGMENT = "Tip : Maintenez CTRL pour tracer un segment";
    private final static String TIP_TERMINER_SEGMENT = "Tip : Relachez le clique gauche pour dessiner le segment";
    private final static String TIP_TERMINER_FIGURE  = "Tip : Clique droit pour fermer le tracé";

    /**
     * Constructeur de la machine a état
     * @param c Canvas auquel la machine est associée
     * @param frameMain Référence à la frame principale
     */
    public FreeDrawMachine(Canvas c, GestureRecognition frameMain) {
        super(c);
        _canvas = c;
        _frameMain = frameMain;
        _gesture = new Gesture();
        _ink = (CPolyLine) _canvas.newPolyLine().setPickable(false).setFilled(false);
    }

    /**
     * Retourne le nom de la machine a état
     * @return Nom de la machine a état
     */
    public String getName() {
        return "FreeDrawMachine";
    }

    /**
     * Etat initial du mode dessin libre
     */
    public State start = new State() {
        boolean isSelectionMultiple = false;

        /**
         * Méthode appelée lors de l'entré dans l'état <b>start</b>.
         * Elle affiche un message d'aide dans la barre de statut.
         */
        public void enter() {
            if (_frameMain.drawMode() == GestureRecognition.MODE_DESSIN_LIBRE) {
            _frameMain._statusBar.isWork(true);
            _frameMain._statusBar.setStatusText(TIP_DESSINER_SEGMENT);
            }
        }

        /**
         * Méthode appelée lors de l'entré dans l'état <b>start</b>.
         * Elle cache les astuces affichées
         */
        public void leave() {
            _frameMain._statusBar.isWork(false);
        }

        // Transition pour la suppression des shapes via la touche (SUPPR)
        Transition deleteShapes = new KeyPress(KeyEvent.VK_DELETE) {

            public void action() {
                _frameMain.deleteShapes(InkMachine.TAG_SHAPE_HOVERED);
            }
        };

        // Transition pour le traçage d'un segment
        Transition beginLine = new Press(BUTTON1, CONTROL, ">> draw") {

            public void action() {
                // Point de départ
                _pInit = getPoint();
                _ink.reset(_pInit.getX(), _pInit.getY()).setDrawable(true).aboveAll();
                _gesture.reset();
                _gesture.addPoint(_pInit.getX(), _pInit.getY());
            }
        };
        
        // Transition pour l'initialisation du dessin a main libre
        Transition begin = new Press(BUTTON1, ">> draw") {

            public void action() {
                // Point de départ
                _pInit = getPoint();
                _ink.reset(_pInit.getX(), _pInit.getY()).setDrawable(true).aboveAll();
                _gesture.reset();
                _gesture.addPoint(_pInit.getX(), _pInit.getY());
            }
        };
    };

    /**
     * Etat dessinant le tracé de l'user.
     */
    public State draw = new State() {
        //Dessine la ligne tracée par l'user + Astuce dans le cas du segment
        Transition dragSegment = new Drag(BUTTON1, CONTROL) {

            public void action() {
                // On informe l'user d'une astuce (selection multiple)
                _frameMain._statusBar.isWork(true);
                _frameMain._statusBar.setStatusText(TIP_TERMINER_SEGMENT);

                _ink.lineTo(getPoint().getX(), getPoint().getY()).setOutlinePaint(_frameMain._borderColor);
                _gesture.addPoint(getPoint().getX(), getPoint().getY());
            }
        };

        //Dessine la ligne tracée par l'user
        Transition drag = new Drag(BUTTON1) {

            public void action() {
                // On informe l'user d'une astuce (fermeture du tracé
                _frameMain._statusBar.isWork(true);
                _frameMain._statusBar.setStatusText(TIP_TERMINER_FIGURE);

                _ink.lineTo(getPoint().getX(), getPoint().getY()).setOutlinePaint(_frameMain._borderColor);
                _gesture.addPoint(getPoint().getX(), getPoint().getY());
            }
        };

        // Fin du tracé du segment
        Transition endLine = new Release(BUTTON1, CONTROL, ">> feedback") {

            public void action() {
                armTimer(100, true);

                if (_frameMain.drawMode() == GestureRecognition.MODE_DESSIN_LIBRE) {
                    // On récupère le cadre de l'suer
                    _gesture.addPoint(getPoint().getX(), getPoint().getY());

                    // On dessine le segment associé
                    _canvas.newSegment(_pInit.getX(), _pInit.getY(),
                            getPoint().getX(), getPoint().getY()).addTag(InkMachine.TAG_SHAPE).setOutlinePaint(_frameMain._borderColor);
                }
            }
        };

        // Fin du tracé, on ferme la figure (rejoint le point initial)
        Transition endFigure = new Press(BUTTON3, ">> feedback") {
            public void action() {
                armTimer(100, true);

                if (_frameMain.drawMode() == GestureRecognition.MODE_DESSIN_LIBRE) {
                    // On récupère le cadre de l'suer
                    _gesture.addPoint(getPoint().getX(), getPoint().getY());

                    // On ferme la figure
                    _ink.close().duplicate().addTag(InkMachine.TAG_SHAPE)
                            .setOutlinePaint(_frameMain._borderColor)
                            .setFilled(true).setFillPaint(_frameMain._backgroundColor);
                }
            }
        };

        // Fin du tracé
        Transition end = new Release(BUTTON1, ">> feedback") {

            public void action() {
                armTimer(100, true);

                if (_frameMain.drawMode() == GestureRecognition.MODE_DESSIN_LIBRE) {
                    _gesture.addPoint(getPoint().getX(), getPoint().getY());

                    // On créer la courbe faite par l'user
                    _ink.duplicate().addTag(InkMachine.TAG_SHAPE).setOutlinePaint(_frameMain._borderColor);
                }
            }
        };
    };

    public State feedback = new State() {

        Transition timeout = new TimeOut(">> start") {

            public void action() {
                _ink.setDrawable(false);
            }
        };
    };
}